<script setup>
// 存储类型
import {useMessage, useNotification} from 'naive-ui'
import {getTimestampFilename} from "@/utils/getDateTime.js";
import {sendToPortByWritable} from "@/utils/toSerial.js";
import {generateCommand} from "@/utils/refactor/index.js";

const props = defineProps({
	scdTab: {
		type: Object,
	},
	opticalTab: {
		type: Object
	}
})
const message = useMessage()
const notification = useNotification()
const storageTypeOptions = [
	{
		label: "捕跟工程数据",
		value: "0x55"
	},
	{
		label: "跟踪相机图像",
		value: "0x66"
	},
	{
		label: "跟踪相机诊断数据",
		value: "0x44"
	},
	{
		label: "大视场星相机工程数据",
		value: "0x88"
	},
	{
		label: "大视场相机诊断工程数据",
		value: "0x99"
	},
	{
		label: "星敏图像",
		value: "0xAA"
	},
	{
		label: "电机数据",
		value: "0xBB"
	},
]
// 初始配置
const initialForm = {
	storageType: "0x55",
	storageInterval: 10,
	interval: 1000 * 60 * 10, // 间隔时间默认[十分钟]
	totalTime: 1000 * 60 * 60 * 72, // 总时长[72小时],
	sendFrameCount: 999999, // 发送帧数
	sendInterval: 0,
	dir: null,
	directoryHandle: null,
	writable: null,
	isRunning: false,
	timeout: 1000,
	currentIndex: 0,

}
// 自动化收遥测配置
const autoStorageForm = reactive(initialForm)
/**
 * 选择存储遥测文件的目录
 * @returns {Promise<void>}
 */
const selectDirectory = async () => {
	try {
		autoStorageForm.directoryHandle = await window.showDirectoryPicker();
		autoStorageForm.dir = autoStorageForm.directoryHandle.name;
	} catch (error) {
		console.error('Failed to select directory:', error);
	}
};

// todo: 记录起始时间和结束时间, 满足指定时间后停止, 然后定时存储到指定目录下
// 设置定时器,每次存10分钟,然后接收串口并写入到文件中

/**
 * 生成一个文件
 * @returns {Promise<void>}
 */
const createFile = async () => {
	try {
		const fileHandle = await autoStorageForm.directoryHandle.getFileHandle(getTimestampFilename() + ".bin", {create: true});
		// 设置当前写入流
		autoStorageForm.writable = await fileHandle.createWritable();
	} catch (error) {
		console.error('Failed to create file:', error);
	}
};

async function handleChunk(value) {
	// 将数据块直接写入文件
	await autoStorageForm.writable.write(value);
}

// 停止存储
let stopStorage = generateCommand("光学头工程遥测存储", {
	"工程遥测存储类型": autoStorageForm.storageType,
	"工程遥测存储使能": "0xaa",
	"工程遥测存储时间间隔时间": autoStorageForm.storageInterval
})
// 开始存储
let startStorage = generateCommand("光学头工程遥测存储", {
	"工程遥测存储类型": autoStorageForm.storageType,
	"工程遥测存储使能": "0x55",
	"工程遥测存储时间间隔时间": autoStorageForm.storageInterval
})
// 停止发送
let stopSend = generateCommand("光学头工程遥测发送", {
	"启动/停止": "0xaa",
	"发送帧数": "0x" + (999999).toString(16).padStart(24 / 4, "0"),
	"发送间隔": autoStorageForm.sendInterval.toString(),
	"工程遥测发送类型": autoStorageForm.storageType
})
// 开始发送
let startSend = generateCommand("光学头工程遥测发送", {
	"启动/停止": "0x55",
	"发送帧数": "0x" + (999999).toString(16).padStart(24 / 4, "0"),
	"发送间隔": autoStorageForm.sendInterval.toString(),
	"工程遥测发送类型": autoStorageForm.storageType
})
console.log(startSend)
// 定时存储
const scheduledStorage = async () => {
	// 生成bin文件
	await createFile()
	await sendToPortByWritable(props.opticalTab.port.writable, stopStorage)
	await sendToPortByWritable(props.opticalTab.port.writable, stopSend)
	console.log("停存指令:", stopStorage, "停发指令:", stopSend)
	console.log("存储指令:", startStorage, "发送指令:", startSend)
	// 发送指令开始存储
	await sendToPortByWritable(props.opticalTab.port.writable, startStorage)
	// 设置间隔时间阻塞在此处等待存储
	await new Promise(resolve => {
		setTimeout(resolve, autoStorageForm.interval)
	})
	// 停止存储开始接收并写入到指定目录中
	await sendToPortByWritable(props.opticalTab.port.writable, stopStorage)
	// 发送帧
	await sendToPortByWritable(props.opticalTab.port.writable, startSend)
	// 读取串口数据直到最后一帧(超时五秒)
	await readSerialData(props.scdTab.port.readable, handleChunk)
	// 停止发送
	await sendToPortByWritable(props.opticalTab.port.writable, stopSend)
	// 完成后关闭文件
	await autoStorageForm.writable.close();
}
let reader;

/**
 * 获取读取流的数据,并写入到文件中
 * @param readableStream
 * @param handleChunk
 * @returns {Promise<void>}
 */
async function readSerialData(readableStream, handleChunk) {
	let firstFrameReceived = false;  // 用于标记是否接收到第一帧
	let timeoutId;

	reader = readableStream.getReader();

	try {
		while (props.scdTab.connected && props.scdTab.port.readable) {
			try {
				const {value, done} = await reader.read();

				if (done) {
					console.log("读取完成或停止标志已触发");
					break;
				}

				if (!firstFrameReceived) {
					// 无限等待第一帧
					firstFrameReceived = true;
					console.log("接收到第一帧，开始接收后续帧");
					await handleChunk(value);
				} else {
					// 对第二帧设置超时机制
					if (timeoutId) {
						clearTimeout(timeoutId);  // 清除前一个超时
					}
					timeoutId = setTimeout(() => {
						console.log("第二帧超时，结束读取");
						reader.cancel();  // 取消读取
					}, autoStorageForm.timeout);

					await handleChunk(value);  // 处理接收到的数据
				}

				// 等待一些时间再处理下一帧
				await new Promise(resolve => setTimeout(resolve, 10));

			} catch (error) {
				console.error(error);
			}
		}
	} finally {
		console.log("释放读取器");
		reader.releaseLock();
	}

	// if (props.scdTab.port.readable) {
	// 	await props.scdTab.port.close();
	// }
}

const startTask = async () => {
	if (!props.scdTab?.port?.readable || !props.opticalTab?.port?.readable) {
		message.error("未连接光学头串口或工程数据串口!")
		return
	}
	if (autoStorageForm.isRunning) {
		message.error("任务运行中不可重复启动")
		return
	}
	autoStorageForm.isRunning = true
	// 执行任务的检查
	if (!autoStorageForm.directoryHandle) {
		message.warning("未选择存储目录!")
		return
	}
	// 计算任务总数
	let taskTotal = Math.floor(autoStorageForm.totalTime / autoStorageForm.interval)
	// 启动任务执行
	for (let i = 0; i < taskTotal; i++) {
		try {
			await scheduledStorage()
		} catch (error) {
			notification.error({
				title: `任务运行中出现错误,当前处于${autoStorageForm.currentIndex}步!`,
				content: error.message
			})
			continue
		}

		// 更新任务进度
		autoStorageForm.currentIndex += 1
	}
	autoStorageForm.isRunning = false
	message.success("任务执行完毕")
}

</script>

<template>
	<n-flex :size="7" class="bg-zinc-800 p-2" vertical>
		<n-h6 type="success" prefix="bar">指令配置:</n-h6>

		<n-flex align="center">
			<n-text>工程遥测存储类型:</n-text>
			<n-select class="w-52" :options="storageTypeOptions" v-model:value="autoStorageForm.storageType"></n-select>
		</n-flex>
		<n-flex align="center">
			<n-text>工程遥测存储时间间隔时间(毫秒):</n-text>
			<n-input class="w-32" v-model:value="autoStorageForm.storageInterval"></n-input>
		</n-flex>
		<n-flex align="center">
			<n-text>发送帧数:</n-text>
			<n-input class="w-32" v-model:value="autoStorageForm.sendFrameCount"></n-input>
		</n-flex>


		<n-h6 type="success" prefix="bar">自动化配置:</n-h6>
		<n-flex align="center">
			<n-text class="text-base">当前次数/总次数:</n-text>
			<n-text class="text-base" type="error">
				{{ autoStorageForm.currentIndex }} / {{
					Math.floor(autoStorageForm.totalTime / autoStorageForm.interval)
				}}
			</n-text>
		</n-flex>

		<n-flex align="center">
			<n-text>间隔(毫秒):</n-text>
			<n-input class="w-fit" v-model:value="autoStorageForm.interval">
				<template #suffix>
					<n-text depth="3">{{ (autoStorageForm.interval / 1000 / 60).toFixed(2) }}分钟</n-text>
				</template>
			</n-input>
		</n-flex>
		<n-flex align="center">
			<n-text>总时长(毫秒):</n-text>
			<n-input class="w-fit" v-model:value="autoStorageForm.totalTime">
				<template #suffix>
					<n-text depth="3">{{ (autoStorageForm.totalTime / 1000 / 60 / 60).toFixed(2) }}小时</n-text>
				</template>
			</n-input>
		</n-flex>

		<n-flex align="center">
			<n-text>接收帧超时设置(毫秒):</n-text>
			<n-input class="w-fit" v-model:value="autoStorageForm.timeout">
				<template #suffix>
					<n-text depth="3">{{ (autoStorageForm.timeout / 1000).toFixed(2) }}秒</n-text>
				</template>
			</n-input>
		</n-flex>

		<n-flex align="center">
			<n-text>存储目录:</n-text>
			<n-text class="text-red-600">
				{{ autoStorageForm.dir ? "/" + autoStorageForm.dir : "未选择目录" }}
			</n-text>
			<n-button @click="selectDirectory" class="w-fit">选择目录</n-button>
		</n-flex>
		<n-button @click="startTask">启动</n-button>
	</n-flex>
</template>

<style scoped>

</style>